/************************************************************************************
    ***********LDChip_Register文件主要编写了LD3320寄存器功能配置的相关函数***********
 					 LD3320 有源晶振 22MHZ  不同的晶振请修改LDChip.h 中的定义值（＃define CLK_IN  22）
************************************************************************************/
#include "ldchip_register.h"
uint8 nLD_Mode = LD_MODE_IDLE;//用来记录当前是在进行ASR识别还是在播放MP3


uint8  bMp3Play=0;						//	用来记录播放MP3的状态
uint32 nMp3StartPos=0;
uint32 nMp3Size=0;
uint32 nMp3Pos=0;
uint32 nCurMp3Pos=0;
uint8  ucRegVal;
uint8  ucHighInt;
uint8  ucLowInt;
uint8  ucStatus;
uint8  ucSPVol=15; 						// MAX=15 MIN=0，Speaker喇叭输出的音量

extern uint8  nAsrStatus;
/************************************************************************
功能描述： 延时函数
注意:			移植过来，使用于LD3320的延时函数，勿改动 
**************************************************************************/
static void LD3320_delay(uint32 uldata)
{
	uint16 i  =  0;
	uint16 j  =  0;
	uint16 k  =  0;
	for (i=0;i<5;i++)
	{
		for (j=0;j<uldata;j++)
		{
			k = 200;
			while(k--);
		}
	}
}
/************************************************************************
功能描述： 芯片硬件初始化
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
void LD_Reset(void)
{
	LD3320_RES_HIGH();
	LD3320_delay(100);
	LD3320_RES_LOW();
	LD3320_delay(100);
	LD3320_RES_HIGH();
	LD3320_delay(100);
	SPIx_CS_LOW();
	LD3320_delay(100);
	SPIx_CS_HIGH();
	LD3320_delay(100);
}
/************************************************************************
功能描述： 通用初始化
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
void LD_Init_Common(void)
{
	bMp3Play=0;
	
	LD_ReadReg(0x06);  //读FIFO
	LD_WriteReg(0x17, 0x35); //对LD3320软件复位
	LD3320_delay(5);
	LD_ReadReg(0x06);  //读FIFO

	LD_WriteReg(0x89, 0x03);  //初始化模拟电路控制
	LD3320_delay(5);
	LD_WriteReg(0xCF, 0x43);   //初始化内部省电模式设置
	LD3320_delay(5);
	LD_WriteReg(0xCB, 0x02);  //读ASR结果(候补4)写入
	
	/*PLL setting*/
	/*整体时钟设置*/
	LD_WriteReg(0x11, LD_PLL_11);       
	if (nLD_Mode == LD_MODE_MP3)
	{
		LD_WriteReg(0x1E, 0x00); 
		LD_WriteReg(0x19, LD_PLL_MP3_19);   
		LD_WriteReg(0x1B, LD_PLL_MP3_1B);   
		LD_WriteReg(0x1D, LD_PLL_MP3_1D);
	}
	else
	{
		LD_WriteReg(0x1E,0x00);
		LD_WriteReg(0x19, LD_PLL_ASR_19); 
		LD_WriteReg(0x1B, LD_PLL_ASR_1B);		
	  LD_WriteReg(0x1D, LD_PLL_ASR_1D);
	}
	LD3320_delay(5);
	
	LD_WriteReg(0xCD, 0x04); //允许DSP休眠
	LD_WriteReg(0x17, 0x4c); //DSP进入休眠
	LD3320_delay(1);
	LD_WriteReg(0xB9, 0x00); //初始化当前添加识别句的字符串长度(拼音字符串)
	LD_WriteReg(0xCF, 0x4F); //MP3初始化和ASR初始化时写入0x4F
	LD_WriteReg(0x6F, 0xFF); //对芯片进行初始化
}
/************************************************************************
功能描述： 	MP3播放初始化函数
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/	
void LD_Init_MP3(void)
{
	nLD_Mode = LD_MODE_MP3;
	LD_Init_Common();

	LD_WriteReg(0xBD, 0x02);
	LD_WriteReg(0x17, 0x48);
	
	LD3320_delay(10);

	LD_WriteReg(0x85, 0x52); 
	LD_WriteReg(0x8F, 0x00);  
	LD_WriteReg(0x81, 0x00);
	LD_WriteReg(0x83, 0x00);
	LD_WriteReg(0x8E, 0xff);
	LD_WriteReg(0x8D, 0xff);
	
  LD3320_delay(1);
	
	LD_WriteReg(0x87, 0xff);
	LD_WriteReg(0x89, 0xff);
	
	LD3320_delay(1);
	
	LD_WriteReg(0x22, 0x00);    
	LD_WriteReg(0x23, 0x00);
	LD_WriteReg(0x20, 0xef);    
	LD_WriteReg(0x21, 0x07);
	LD_WriteReg(0x24, 0x77);          
  LD_WriteReg(0x25, 0x03);
  LD_WriteReg(0x26, 0xbb);    
  LD_WriteReg(0x27, 0x01); 
}
/************************************************************************
功能描述： 	实际上是AsrInit函数
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/	
void LD_AsrStart(void)
{
	nLD_Mode=LD_MODE_ASR_RUN;
	LD_Init_Common();

	LD_WriteReg(0xBD, 0x00);//设置LD3320为语音识别模块	
	LD_WriteReg(0x17, 0x48);//激活DSP
	
	LD3320_delay( 5 );

	LD_WriteReg(0x3C, 0x80);//3C:FIFO_EXT下限低8位   
	LD_WriteReg(0x3E, 0x07);//3E:FIFO_EXT下限高8位
	LD_WriteReg(0x38, 0xff);//38:FIFO_EXT上限低8位 
	LD_WriteReg(0x3A, 0x07);//3A:FIFO_EXT上限高8位 
	LD_WriteReg(0x40, 0);   //40:FIFO_EXT MCU水线低8位      
	LD_WriteReg(0x42, 8);		//42:FIFO_EXT MCU水线高8位
	LD_WriteReg(0x44, 0);   //44:FIFO_EXT DSP水线低8位
	LD_WriteReg(0x46, 8);   //46:FIFO_EXT DSP水线高8位
	LD3320_delay( 1 );
}

/************************************************************************
功能描述： 检测 ASR 是否忙状态， 返回1为空闲状态 
检查部位:  B2寄存器
返回函数： 1:成功
**************************************************************************/
uint8 LD_Check_ASRBusyFlag_b2(void)
{
	uint8 j;
	uint8 flag = 0;
	for (j=0; j<10; j++)
	{
		if (LD_ReadReg(0xb2) == 0x21)
		{
			flag = 1;
			break;
		}
		LD3320_delay(10);		
	}
	return flag;
}
/************************************************************************
功能描述： 添加识别关键词语
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
// Return 1: success.
//	添加识别关键词语
uint8 LD_AsrAddFixed(void)
{
	uint8 k, flag;
	uint8 nAsrAddLength;
	
	
	/*！！！添加关键词*/
	const uint8 pCode[Number_of_Keywords] = {CODE_KAIDENG,CODE_GUANDENG,CODE_KAIMEN,CODE_GUANMEN,CODE_KAIKONGTIAO,
																					 CODE_GUANKONGTIAO,CODE_CHUSHI,CODE_ZHILENG,CODE_DAFENG,CODE_ZHONGFENG,CODE_WEIFENG,
																					 CODE_SAOFENG,CODE_DINGXIANG,CODE_SHUIMIAN,CODE_TUICHUSHUIMIAN,
																					 CODE_16,CODE_17,CODE_18,CODE_19,CODE_20,CODE_21,CODE_22,CODE_23,CODE_24,
																					 CODE_25,CODE_26,CODE_27,CODE_28,CODE_29,CODE_30,ALL_OFF};
	
	const char sRecog[Number_of_Keywords][Length_of_Keyword] = {"kai deng","guan deng","kai men","guan men","kai kong tiao","guan kong tiao",
																															"chu shi","zhi leng","da feng","zhong feng","wei feng",
																															"sao feng","ding xiang","shui mian","tui chu shui mian",
																															"shi liu du","shi qi du","shi ba du","shi jiu du","er shi du","er shi yi du",
																															"er shi er du","er shi san du","er shi si du","er shi wu du","er shi liu du",
																															"er shi qi du","er shi ba du","er shi jiu du","san shi du","quan guan"};
	
	flag = 1;
	for (k=0; k<Number_of_Keywords; k++)
	{			
		if(LD_Check_ASRBusyFlag_b2() == 0)
		{
			flag = 0;
			break;
		}
			LD_WriteReg(0xc1, pCode[k] );//识别字index(00H-FFH)
			LD_WriteReg(0xc3, 0 );//告诉芯片要识别字
			LD_WriteReg(0x08, 0x04);//清除FIFO_EXT
			LD3320_delay(1);
			LD_WriteReg(0x08, 0x00);//清除FIFO后要写入一次0x00
			LD3320_delay(1);

			for (nAsrAddLength=0; nAsrAddLength<20; nAsrAddLength++)
			{
				if (sRecog[k][nAsrAddLength] == 0)
				break;
				LD_WriteReg(0x5, sRecog[k][nAsrAddLength]);//识别字符串写入FIFO_EXT
			}
			LD_WriteReg(0xb9, nAsrAddLength);//告诉芯片当前识别字的字符串长度
			LD_WriteReg(0xb2, 0xff);//???
			LD_WriteReg(0x37, 0x04);//告诉DSP要添加一项识别句
		} 
    return flag;
}
/************************************************************************
功能描述： 
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
// Return 1: success.
uint8 LD_AsrRun(void)
{
	LD_WriteReg(0x35, MIC_VOL);//设置麦克风音量
	LD_WriteReg(0x1C, 0x09);//ADC开关保留
	LD_WriteReg(0xBD, 0x20);//初始化控制寄存器保留
	LD_WriteReg(0x08, 0x01);//清除FIFO_DATA
	LD3320_delay( 5 );
	LD_WriteReg(0x08, 0x00);//清一次FIFO后要写0x00
	LD3320_delay( 5 );

	if(LD_Check_ASRBusyFlag_b2() ==0)
	{
		return 0;
	}

	LD_WriteReg(0xB2, 0xff);//???	
	LD_WriteReg(0x37, 0x06);//告诉DSP开始语音识别
	//LD_WriteReg(0x37, 0x06);
	LD3320_delay(5);
	LD_WriteReg(0x1C, 0x0b);//麦克风输入ADC通道可用
	LD_WriteReg(0x29, 0x10);//中断允许
	LD_WriteReg(0xBD, 0x00);//LD3320为语音识别模块   
	return 1;
}
/************************************************************************************/
//	RunASR()函数实现了一次完整的ASR语音识别流程
//	LD_AsrStart() 函数实现了ASR初始化
//	LD_AsrAddFixed() 函数实现了添加关键词语到LD3320芯片中
//	LD_AsrRun()	函数启动了一次ASR语音识别流程
//
//	任何一次ASR识别流程，都需要按照这个顺序，从初始化开始进行
/************************************************************************************/

uint8 RunASR(void)
{
	uint8 i=0;
	uint8 asrflag=0;
	for (i=0; i<5; i++)			//	防止由于硬件原因导致LD3320芯片工作不正常，所以一共尝试5次启动ASR识别流程
	{
		LD_AsrStart();			//初始化ASR
		LD3320_delay(100);
		if (LD_AsrAddFixed()==0)	//添加关键词语到LD3320芯片中
		{
			LD_Reset();			//	LD3320芯片内部出现不正常，立即重启LD3320芯片
			LD3320_delay(50);	//	并从初始化开始重新ASR识别流程
			continue;
		}

		LD3320_delay(10);

		if (LD_AsrRun() == 0)
		{
			LD_Reset();			//	LD3320芯片内部出现不正常，立即重启LD3320芯片
			LD3320_delay(50);	//	并从初始化开始重新ASR识别流程
			continue;
		}

		asrflag=1;
		break;					//	ASR流程启动成功，退出当前for循环。开始等待LD3320送出的中断信号
	}
	return asrflag;
}

/************************************************************************
功能描述： 	ASR识别处理函数 ，可以利用查询方式，或中断方式进行调用
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
void ASR_IRQHandler(void)
{
	uint8 nAsrResCount=0;

	ucRegVal = LD_ReadReg(0x2B);
	
		// 语音识别产生的中断
		// （有声音输入，不论识别成功或失败都有中断）
	LD_WriteReg(0x29,0) ;
	LD_WriteReg(0x02,0) ;

	 if((ucRegVal & 0x10) && LD_ReadReg(0xb2)==0x21 && LD_ReadReg(0xbf)==0x35)		
	{	 
		nAsrResCount = LD_ReadReg(0xba);
		if(nAsrResCount>0 && nAsrResCount<=4) 
	 {
		nAsrStatus=LD_ASR_FOUNDOK; 				
	 }
	  else
	 {
		nAsrStatus=LD_ASR_FOUNDZERO;
	 }	
	}
		else
	{	
		nAsrStatus=LD_ASR_FOUNDZERO;	//执行没有识别
	}
		LD_WriteReg(0x2b, 0);    //清空中断请求编号
    LD_WriteReg(0x1C,0);	 //ADC开关 设为不可用
		LD_WriteReg(0x29,0);
		LD_WriteReg(0x02,0);
		LD_WriteReg(0x2B,0);
		LD_WriteReg(0xBA,0);	
		LD_WriteReg(0xBC,0);	
		LD_WriteReg(0x08,1);//清除FIFO_DATA
		LD_WriteReg(0x08,0);//清除FIFO_DATA后 再次写0
}
/************************************************************************
功能描述： 	喇叭Speaker音量调节(写寄存器0x8e)
注意		: 	耳机的音量也是可以调节的，使用寄存器 81（左耳音量）和 83（右耳音量）。
						2个寄存器都是只有第 1-5 位有效，共 32 级，而且这 5 位都为 0（00000B）
						的时候是音量最大的，都为 1（11111B）的时候音量最小
**************************************************************************/
void LD_AdjustMIX2SPVolume(uint8 val)
{
	ucSPVol = val;
	val = ((15-val)&0x0f) << 2;
	LD_WriteReg(0x8E, val | 0xc3); 
	LD_WriteReg(0x87, 0x78); 
}

/************************************************************************
功能描述： 	MP3播放数据装载函数
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
void LD_ReloadMp3Data(void)
{
}
/************************************************************************
功能描述： 	MP3播放函数
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
void LD_play()
{
	nMp3Pos=0;
	bMp3Play=1;

	if (nMp3Pos >=  nMp3Size)
		return ; 

	LD_ReloadMp3Data();

  LD_WriteReg(0xBA, 0x00);
	LD_WriteReg(0x17, 0x48);
	LD_WriteReg(0x33, 0x01);
	LD_WriteReg(0x29, 0x04);
	
	LD_WriteReg(0x02, 0x01); 
	LD_WriteReg(0x85, 0x5A);

}
/************************************************************************
功能描述： 	MP3播放处理函数 ，可以利用查询方式，或中断方式进行调用
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
void MP3_IRQHandler(void)
{
	
}
/************************************************************************
功能描述： 	获取识别结果
调用函数： 
入口参数： 
返回函数： 
**************************************************************************/
uint8 LD_GetResult(void)
{
	return LD_ReadReg(0xc5);
}



